package com.xxy.crm.service;

import com.xxy.crm.base.BaseService;
import com.xxy.crm.dao.UserMapper;
import com.xxy.crm.dao.UserRoleMapper;
import com.xxy.crm.model.UserModel;
import com.xxy.crm.utils.AssertUtil;
import com.xxy.crm.utils.Md5Util;
import com.xxy.crm.utils.PhoneUtil;
import com.xxy.crm.utils.UserIDBase64;
import com.xxy.crm.vo.User;
import com.xxy.crm.vo.UserRole;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service
public class UserService extends BaseService<User,Integer> {
    @Resource
    private UserMapper userMapper;
    @Resource
    private UserRoleMapper userRoleMapper;

    /**
     * 登录
     * @param userName
     * @param userPwd
     * @return
     */
    public UserModel userLogin(String userName,String userPwd){

        //验证参数
        checkLoginParams(userName,userPwd);
        // 2. 根据⽤户名，查询⽤户对象
        User user = userMapper.queryUserByUserName(userName);
        // 3. 判断⽤户是否存在 (⽤户对象为空，记录不存在，⽅法结束)
        AssertUtil.isTrue(user==null,"⽤户不存在或已注销！");
        // 4. ⽤户对象不为空（⽤户存在，校验密码。密码不正确，⽅法结束）
        checkLoginPwd(userPwd,user.getUserPwd());
        return buildUserInfo(user);
    }
    private UserModel buildUserInfo(User user) {
        UserModel userModel = new UserModel();
        //设置用户参数
        /*userModel.setUserId(user.getId());*/
        userModel.setUserIdStr(UserIDBase64.encoderUserID(user.getId()));
        userModel.setUserName(user.getUserName());
        userModel.setTrueName(user.getTrueName());
        return userModel;
    }

    /**
     * 验证登录密码
     * @param userPwd 前台传递的密码
     * @param upwd 数据库中查询到的密码
     * @return
     */
    private void checkLoginPwd(String userPwd, String upwd) {
        // 数据库中的密码是经过加密的，将前台传递的密码先加密，再与数据库中的密码作⽐较
        userPwd = Md5Util.encode(userPwd);
        //比较密码
        AssertUtil.isTrue(!userPwd.equals(upwd),"⽤户密码不正确！");

    }

    /**
     * 验证⽤户登录参数
     * @param userName
     * @param userPwd
     */
    private void checkLoginParams(String userName, String userPwd) {
        //判断姓名
        AssertUtil.isTrue(StringUtils.isBlank(userName),"⽤户姓名不能为空！");
        //判断密码
        AssertUtil.isTrue(StringUtils.isBlank(userPwd),"⽤户密码不能为空！");
    }


    /**
     * ⽤户密码修改
     * 1. 参数校验
     * userId ⾮空 ⽤户对象必须存在
     * oldPassword ⾮空 与数据库中密⽂密码保持⼀致
     * newPassword ⾮空 与原始密码不能相同
     * confirmPassword ⾮空 与新密码保持⼀致
     * 2. 设置⽤户新密码
     * 新密码进⾏加密处理
     * 3. 执⾏更新操作
     * 受影响的⾏数⼩于1，则表示修改失败
     * ⽤户密码修改
     * 1. 参数校验
     * ⽤户ID：userId ⾮空 ⽤户对象必须存在
     * 原始密码：oldPassword ⾮空 与数据库中密⽂密码保持⼀致
     * 新密码：newPassword ⾮空 与原始密码不能相同
     * 确认密码：confirmPassword ⾮空 与新密码保持⼀致
     * 2. 设置⽤户新密码
     * 新密码进⾏加密处理
     * 3. 执⾏更新操作
     * 受影响的⾏数⼩于1，则表示修改失败
     *
     * 注：在对应的更新⽅法上，添加事务控制
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void updateUserPassword(Integer userId,String oldPwd,String newPwd,String repeatPwd){
        // 通过userId获取⽤户对象
        User user = userMapper.selectByPrimaryKey(userId);
        // 1. 参数校验
        checkPasswordParams(user,oldPwd,newPwd,repeatPwd);
        // 2. 设置⽤户新密码
        user.setUserPwd(Md5Util.encode(newPwd));
        // 3. 执⾏更新操作
        AssertUtil.isTrue(userMapper.updateByPrimaryKeySelective(user)<1,"⽤户密码更新失败！");
    }

    /**
     * 参数判断
     * @param user
     * @param oldPwd
     * @param newPwd
     * @param repeatPwd
     */
    private void checkPasswordParams(User user, String oldPwd, String newPwd, String repeatPwd) {
        // user对象 ⾮空验证
        AssertUtil.isTrue(user ==null,"⽤户未登录或不存在！");
        // 原始密码 ⾮空验证
        AssertUtil.isTrue(StringUtils.isBlank(oldPwd),"请输⼊原始密码！");
        // 原始密码要与数据库中的密⽂密码保持⼀致
        AssertUtil.isTrue(!(user.getUserPwd().equals(Md5Util.encode(oldPwd))),"原始密码不正确！");
        // 新密码 ⾮空校验
        AssertUtil.isTrue(StringUtils.isBlank(newPwd),"请输⼊新密码！");
        // 新密码与原始密码不能相同
        AssertUtil.isTrue(oldPwd.equals(newPwd),"新密码不能与原始密码相同！");
        //确认密码 ⾮空校验
        AssertUtil.isTrue(StringUtils.isBlank(repeatPwd),"请输⼊确认密码！");
        // 新密码要与确认密码保持⼀致
        AssertUtil.isTrue(!(newPwd.equals(repeatPwd)),"新密码与确认密码不⼀致！");
    }

    /**
     * 查询所有的销售人员
     * @return
     */
    public List<Map<String,Object>> queryAllSales(){
        return userMapper.queryAllSales();
    }

    /**
     * 添加用户
     *  1. 参数校验
     *      用户名userName     非空，唯一性
     *      邮箱email          非空
     *      手机号phone        非空，格式正确
     *  2. 设置参数的默认值
     *      isValid           1
     *      createDate        系统当前时间
     *      updateDate        系统当前时间
     *      默认密码            123456 -> md5加密
     *  3. 执行添加操作，判断受影响的行数
     *
     *
     * 乐字节：专注线上IT培训
     * 答疑老师微信：lezijie
     * @param user
     * @return void
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void addUser(User user){
        //参数校验
        /* 1. 参数校验 */
        checkUserParams(user.getUserName(), user.getEmail(), user.getPhone(),null);
        //设置参数默认值
        user.setIsValid(1);
        user.setCreateDate(new Date());
        user.setUpdateDate(new Date());
        //设置默认密码，需要进行Md5加密
        user.setUserPwd(Md5Util.encode("123456"));
        //执行新增方法，判断受影响的行数
        AssertUtil.isTrue(userMapper.insertSelective(user)!= 1,"用户添加失败");
        System.out.println(user);

        //用户角色关联，每个用户都有对应的角色信息
        //用户是userId,角色是roleIds
        relationUserRole(user.getId(),user.getRoleIds());
    }

    /**
     * 用户角色关联
     *  添加操作
     *      原始角色不存在
     *          1. 不添加新的角色记录    不操作用户角色表
     *          2. 添加新的角色记录      给指定用户绑定相关的角色记录
     *
     *  更新操作
     *      原始角色不存在
     *          1. 不添加新的角色记录     不操作用户角色表
     *          2. 添加新的角色记录       给指定用户绑定相关的角色记录
     *      原始角色存在
     *          1. 添加新的角色记录       判断已有的角色记录不添加，添加没有的角色记录
     *          2. 清空所有的角色记录     删除用户绑定角色记录
     *          3. 移除部分角色记录       删除不存在的角色记录，存在的角色记录保留
     *          4. 移除部分角色，添加新的角色    删除不存在的角色记录，存在的角色记录保留，添加新的角色
     *
     *   如何进行角色分配？？？
     *      判断用户对应的角色记录存在，先将用户原有的角色记录删除，再添加新的角色记录
     *
     *  删除操作
     *      删除指定用户绑定的角色记录
     *
     * @param userId  用户ID
     * @param roleIds 角色ID
     * @return
     */
    private void relationUserRole(Integer userId, String roleIds) {
        //通过用户id查询角色记录
        Integer count = userRoleMapper.countUserRoleById(userId);
        //判断角色记录是否存在
        if (count>0){
            //如果角色记录存在，则删除该用户对应的角色记录
            AssertUtil.isTrue(userRoleMapper.deleteUserRoleById(userId) !=count,"用户记录删除失败");
        }
        //判断角色id是否存在，如果存在就添加对应的角色记录
        if (StringUtils.isNotBlank(roleIds)){
            //将角色记录添加到集合中，进行批量添加的操作
            List<UserRole> userRoleList = new ArrayList<>();
            //将角色id由字符串转变为数组
            String[] roleIdArray = roleIds.split(",");
            //遍历数组，赋值并且添加到集合中
            for (String roleId :roleIdArray){
                UserRole userRole = new UserRole();
                userRole.setRoleId(Integer.parseInt(roleId));
                userRole.setUserId(userId);
                userRole.setCreateDate(new Date());
                userRole.setUpdateDate(new Date());
                //设置到集合中
                userRoleList.add(userRole);
            }
            //添加用户角色记录
            AssertUtil.isTrue(userRoleMapper.insertBatch(userRoleList)!=userRoleList.size(),"用户角色分配失败");
        }
    }


    /**
     *用户名userName     非空，唯一性
     *邮箱email          非空
     *手机号phone        非空，格式正确
     */
    private void checkUserParams(String userName, String email, String phone,Integer userId) {
        AssertUtil.isTrue(StringUtils.isBlank(userName),"用户名不能为空");
        //判断用户名的唯一性
        // 如果用户对象为空，则表示用户名可用；如果用户对象不为空，则表示用户名不可用
        // 如果是添加操作，数据库中无数据，只要通过名称查到数据，则表示用户名被占用
        // 如果是修改操作，数据库中有对应的记录，通过用户名查到数据，可能是当前记录本身，也可能是别的记录
        // 如果用户名存在，且与当前修改记录不是同一个，则表示其他记录占用了该用户名，不可用
        User temp  = userMapper.queryUserByUserName(userName);
        AssertUtil.isTrue(null != temp && !(temp.getId().equals(userId)),"用户名已存在");
        //判读邮箱非空
        AssertUtil.isTrue(StringUtils.isBlank(email),"邮箱不能为空");
        //判断手机号非空
        AssertUtil.isTrue(StringUtils.isBlank(phone),"手机号不能为空");
        //判断手机号格式
        AssertUtil.isTrue(!PhoneUtil.isMobile(phone),"手机号格式不正确");
    }


    /**
     * 更新用户
     *  1. 参数校验
     *      判断用户ID是否为空，且数据存在
     *      用户名userName     非空，唯一性
     *      邮箱email          非空
     *      手机号phone        非空，格式正确
     *  2. 设置参数的默认值
     *      updateDate        系统当前时间
     *  3. 执行更新操作，判断受影响的行数
     *

     * @param user
     * @return void
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void updateUser(User user){
        //判断用户ID是否为空，且数据存在
        AssertUtil.isTrue(null == user.getId(),"待更新记录不存在");
        //通过id查找记录
        User temp = userMapper.selectByPrimaryKey(user.getId());
        AssertUtil.isTrue(null == temp,"待更新记录不存在");
        //参数校验
        checkUserParams(user.getUserName(), user.getEmail(), user.getPhone(),user.getId());
        user.setUpdateDate(new Date());
        AssertUtil.isTrue(userMapper.updateByPrimaryKeySelective(user)!=1,"用户更新失败");

        //用户角色关联，每个用户都有对应的角色信息
        //用户是userId,角色是roleIds
        relationUserRole(user.getId(),user.getRoleIds());
    }

    /**
     * 删除用户
     * @param ids
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void deleteByIds(Integer[] ids) {
        //判断ids是否为空，长度是否大于0
        AssertUtil.isTrue(ids == null && ids.length>0,"待删除记录不存在");
        //执行删除记录，影响受影响行数
        AssertUtil.isTrue(userMapper.deleteBatch(ids)!=ids.length,"用户删除失败");
        //遍历用户id的数组
        for(Integer id:ids){
            //通过id查询对应用户的角色记录
            Integer count = userRoleMapper.countUserRoleById(id);
            //判断用户角色是否存在
            if (count>0){
                AssertUtil.isTrue(userRoleMapper.deleteUserRoleById(id)!=count,"删除错误");
            }
        }
    }
}
